# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Querying explain this vulnerability prompt', feature_category: :vulnerability_management do
  include GraphqlHelpers

  let(:identifiers) { vulnerability.finding.identifiers.pluck(:name).join(", ") }
  let(:fields) do
    <<~GRAPHQL
      promptWithCode
      promptWithoutCode
      presubmissionChecks { potentialSecretsInCode secretDetectionResult }
    GRAPHQL
  end

  let(:arguments) { { vulnerabilityId: vulnerability.to_gid } }
  let(:query) { graphql_query_for('explainVulnerabilityPrompt', arguments, fields) }

  let_it_be(:source_code) do
    <<~SOURCE
    #include <stdio.h>

    int main(int argc, char *argv[])
    {
      char buf[8];
      memcpy(&buf, "123456789");
      printf("hello, world!");
    }
    SOURCE
  end

  let_it_be(:project) do
    create(:project, :custom_repo, files: {
      'src/main.c' => source_code
    })
  end

  let_it_be(:vulnerability_finding) do
    create(:vulnerabilities_finding,
      :sast,
      project: project,
      location: {
        'file' => 'src/main.c',
        'start_line' => 5,
        'end_line' => 6
      }
    )
  end

  let_it_be(:user) { create(:user, security_dashboard_projects: [project]) }
  let_it_be(:authorized_user) do
    create(:user, security_dashboard_projects: [project]).tap do |user|
      project.add_developer(user)
    end
  end

  let_it_be(:vulnerability) do
    create(:vulnerability, findings: [vulnerability_finding], project: project)
  end

  let(:current_user) { user }

  before do
    stub_licensed_features(security_dashboard: true)

    post_graphql(query, current_user: current_user)
  end

  context 'when user is not logged in' do
    let(:current_user) { nil }

    subject { graphql_data['explainVulnerabilityPrompt'] }

    it 'returns nothing' do
      post_graphql(query, current_user: current_user)

      expect(subject).to be_nil
    end
  end

  context 'when user is not permitted on the project' do
    subject { graphql_data['explainVulnerabilityPrompt'] }

    it 'returns nothing' do
      post_graphql(query, current_user: current_user)

      expect(subject).to be_nil
    end
  end

  context 'when user is logged in and permitted' do
    let(:current_user) { authorized_user }

    before do
      post_graphql(query, current_user: current_user)
    end

    describe 'prompt_with_code' do
      subject { graphql_data.dig('explainVulnerabilityPrompt', 'promptWithCode') }

      context 'when the vulnerability has code' do
        it do
          is_expected.to eq(
            <<~PROMPT
              You are a software vulnerability developer.
              Explain the vulnerability \"#{vulnerability.title} - ()\".
              The file \"main.c\" has this vulnerable code:

              ```
                char buf[8];
                memcpy(&buf, \"123456789\");

              ```

              Provide a code example with syntax highlighting on how an attacker can take advantage of the vulnerability.
              Provide a code example with syntax highlighting on how to fix it.
              Provide the response in markdown format with headers.
            PROMPT
          )
        end
      end

      context 'when the vulnerability does not have code' do
        let!(:vulnerability) { create(:vulnerability, :sast, :with_finding, project: project) }

        it { is_expected.to be_nil }
      end
    end

    describe 'prompt_without_code' do
      subject { graphql_data.dig('explainVulnerabilityPrompt', 'promptWithoutCode') }

      context 'when the vulnerability has code' do
        it do
          is_expected.to eq(
            <<~PROMPT
              You are a software vulnerability developer.
              Explain the vulnerability \"#{vulnerability.title} - ()\".
              The vulnerable code is in the file "main.c".
              Provide a code example with syntax highlighting on how an attacker can take advantage of the vulnerability.
              Provide a code example with syntax highlighting on how to fix it.
              Provide the response in markdown format with headers.
          PROMPT
          )
        end
      end

      context 'when the vulnerability does not have code' do
        let!(:vulnerability) { create(:vulnerability, :sast, :with_finding, project: project) }

        it do
          is_expected.to eq(
            <<~PROMPT
              You are a software vulnerability developer.
              Explain the vulnerability \"#{vulnerability.title} - (CVE-2018-1234)\".
              The vulnerable code is in the file "App.java".
              Provide a code example with syntax highlighting on how an attacker can take advantage of the vulnerability.
              Provide a code example with syntax highlighting on how to fix it.
              Provide the response in markdown format with headers.
          PROMPT
          )
        end
      end
    end
  end
end
